package com.mega.fe.util;


import com.mega.fe.util.klass.InstrumentationHelper;
import com.mega.fe.util.klass.McInstGetter;
import net.minecraft.world.entity.Entity;

import java.lang.instrument.ClassDefinition;
import java.util.HashMap;

public class MEGA_SUPER extends MEGA {
    public static HashMap<String, Class<?>> mapping = new HashMap<>();

    public static boolean has(String klassName) {
        return mapping.containsKey(klassName);
    }
    public static void Unsafely_AttackTarget(Object sharky) {
        boolean isClass = sharky instanceof Class<?>;
        Class<?> klass = isClass ? (Class<?>) sharky : sharky.getClass();
        try {
            Class<?> wow = toClass(klass, ()->removeMethodsTransform(klass));
            if (isClass)
                replaceClass((Class<?>) sharky, wow);
            else {
                replaceClass(sharky, wow);
                replaceClass(sharky.getClass(), wow);
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }

    public static synchronized void Attack_Target(Object sharky) {
        if (sharky instanceof Entity e && BaseInit.isDeath(e))
            return;
        boolean isClass = sharky instanceof Class<?>;
        Class<?> klass = isClass ? (Class<?>) sharky : sharky.getClass();
        Attack_Target(sharky, MEGA.bytesOfClass(klass));
    }

    public static synchronized Class<?> Attack_Target(Object sharky, byte[] baseBytes) {
        boolean isClass = sharky instanceof Class<?>;
        Class<?> klass = isClass ? (Class<?>) sharky : sharky.getClass();
        try {
            Class<?> wow = checkAndReturnClass(new TransformInfo(sharky, klass, isClass, baseBytes));
            if (isClass)
                replaceClass((Class<?>) sharky, wow);
            else {
                replaceClass(sharky, wow);
                replaceClass(sharky.getClass(), wow);
            }
            return wow;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return klass;
    }

    public static synchronized void AgentAttack_Target(Object sharky) {
        boolean isClass = sharky instanceof Class<?>;
        Class<?> klass = isClass ? (Class<?>) sharky : sharky.getClass();
        AgentAttack_Target(sharky, MEGA.bytesOfClass(klass));
    }

    public static synchronized void AgentAttack_Target(Object sharky, byte[] baseBytes) {
        boolean isClass = sharky instanceof Class<?>;
        Class<?> klass = isClass ? (Class<?>) sharky : sharky.getClass();
        try {
            ClassDefinition cd = new ClassDefinition(klass, checkAndReturnBytes(new TransformInfo(sharky, klass, isClass, baseBytes)));
            InstrumentationHelper.getInstrumentation().redefineClasses(cd);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
    /**
    public static Class<?> No_CheckToClass(Class<?> sharky, Supplier<byte[]> supplier) throws Throwable {
        return new DefineClassLoader().myDefineClass(sharky.getName(), supplier.get(), 0, supplier.get().length);
    }

    public static void No_Check() {
        Class<?> klass = Method.class;
        try {
            Class<?> wow = No_CheckToClass(klass, ()->noneCheckTransform(klass));
            replaceClass(klass, wow);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
     @auther mega
     @deprecated no way..
     **/
    public record TransformInfo(Object sharky, Class<?> klass, boolean isClass, byte[] baseBytes) {}

    /**
     *
     * @param ti includes the transforming-class info
     * @return return a Class<?></?> which has been transformed.If not , transform it and return
     */
    public static Class<?> checkAndReturnClass(TransformInfo ti) throws Throwable {
        String Kname = ti.klass.getName();
        boolean isTransformed = Kname.endsWith("$allreturned2_mega_modified");
        if (isTransformed)
            return mapping.get(Kname);
        else return toClass_allreturn2(ti.klass, ()-> {
            try {
                return allReturnTransform(ti.isClass ? (Class<?>) ti.sharky : ti.sharky.getClass(), ti.baseBytes);
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        });
    }

    public static byte[] checkAndReturnBytes(TransformInfo ti) throws Throwable {
        String Kname = ti.klass.getName();
        boolean isTransformed = Kname.endsWith("$allreturned2_mega_modified");
        if (isTransformed)
            return ti.baseBytes;
        else return allReturnTransform(ti.isClass ? (Class<?>) ti.sharky : ti.sharky.getClass(), ti.baseBytes);
    }
}
